package ar.com.fiuba.service.impl;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import ar.com.fiuba.SystemKeys;
import ar.com.fiuba.application.api.CoefficientCalculationStrategySelector;
import ar.com.fiuba.domain.CoefficientCalculationStrategy;
import ar.com.fiuba.domain.Word;
import ar.com.fiuba.domain.api.Dictionary;
import ar.com.fiuba.domain.api.WordFactory;
import ar.com.fiuba.domain.exceptions.DomainException;
import ar.com.fiuba.domain.impl.Corrector;
import ar.com.fiuba.domain.impl.misspell.MisspelledWordsGenerator;
import ar.com.fiuba.service.api.Service;

public class ReportService implements Service {

	private CoefficientCalculationStrategySelector coefficientCalculationStrategySelector;

	private Dictionary dictionary;

	private WordFactory wordFactory;

	private List<MisspelledWordsGenerator> misspelledWordsGenerators;

	private String reportOutputFolder = "";

	public ReportService(CoefficientCalculationStrategySelector coefficientCalculationStrategySelector,
			Dictionary dictionary, WordFactory wordFactory, List<MisspelledWordsGenerator> misspelledWordGenerators) {
		this.coefficientCalculationStrategySelector = coefficientCalculationStrategySelector;
		this.dictionary = dictionary;
		this.wordFactory = wordFactory;
		this.misspelledWordsGenerators = misspelledWordGenerators;
	}

	public void run(Map<String, String> parameters) {
		String coefficientAlgorythm = parameters.get(SystemKeys.COEFFICIENT_ALGORYTHM);
		setReportOutputFolder(parameters.get(SystemKeys.REPORT_OUTPUT_FOLDER));

		CoefficientCalculationStrategy coefficientCalculationStrategy = resolveStrategy(coefficientAlgorythm);
		Corrector corrector = new Corrector(dictionary, coefficientCalculationStrategy);

		for (MisspelledWordsGenerator wordsGenerator : misspelledWordsGenerators) {
			try {
				buildReport(corrector, wordsGenerator);
			} catch (IOException e) {
				// TODO Assuming no errors writting files.
				e.printStackTrace();
			}
		}
	}

	private void buildReport(Corrector corrector, MisspelledWordsGenerator wordsGenerator) throws IOException {
		List<String> expectedWords = wordsGenerator.getCorrectWordsArray();
		buildIndividualReport(corrector, wordsGenerator.generateErrorAtTheBeginning(), expectedWords, wordsGenerator.getFileNamePrefix() + "Start");
		buildIndividualReport(corrector, wordsGenerator.generateErrorInTheMiddle(), expectedWords, wordsGenerator.getFileNamePrefix() + "Middle");
		buildIndividualReport(corrector, wordsGenerator.generateErrorAtTheEnd(), expectedWords, wordsGenerator.getFileNamePrefix() + "End");
	}

	private void buildIndividualReport(Corrector corrector, List<String> wordsWithErrors, List<String> expectedWords, String fileName) throws IOException {
		int wordsCount = 0;
		int correctedCount = 0;
		Word correctedWord = Word.NullWord();
		
		BufferedWriter out = new BufferedWriter(new FileWriter(getReportOutputFolder() + fileName + ".csv"));
	
		for (String misspelledWord : wordsWithErrors) {
			try {
				correctedWord = corrector.getBestMatch(wordFactory.makeWord(misspelledWord));
			} catch (DomainException e) {
				// Assuming valid length of word/n-gramm.
				e.printStackTrace();
			}
			String correctedWordValue = correctedWord.getValue();
			String expectedWord = expectedWords.get(wordsCount);
			out.write(misspelledWord + "," + correctedWordValue + "," + expectedWord + "\n");
			if (correctedWordValue.equals(expectedWord))
				correctedCount++;
			wordsCount++;
		}
		out.close();

		BufferedWriter resultsBuffer = new BufferedWriter(new FileWriter(getReportOutputFolder() + "results.txt", true));
		resultsBuffer.write(fileName + " - total: " + wordsWithErrors.size() + ", corrected: " + correctedCount + "\n");
		resultsBuffer.close();

	}

	private CoefficientCalculationStrategy resolveStrategy(String coefficientAlgorythm) {
		return coefficientCalculationStrategySelector.resolveCoefficientCalculationStrategy(coefficientAlgorythm);
	}

	private void setReportOutputFolder(String reportOutputFolder) {
		this.reportOutputFolder = reportOutputFolder;
	}

	private String getReportOutputFolder() {
		return reportOutputFolder;
	}

}
